package com.wx.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.StringPart;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.io.IOUtils;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.type.TypeReference;
import com.github.pagehelper.PageHelper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.wx.commons.SentMassJob;
import com.wx.core.process.WxApi;
import com.wx.entity.SysWxuser;
import com.wx.entity.WxFansGroup;
import com.wx.entity.WxFansGroupExample;
import com.wx.entity.WxFansUser;
import com.wx.entity.WxMassAndSendResult;
import com.wx.entity.WxMassMessage;
import com.wx.entity.WxMassMessageExample;
import com.wx.entity.WxMassMessageHis;
import com.wx.entity.WxMassSendResult;
import com.wx.entity.WxMulReply;
import com.wx.entity.WxPicReply;
import com.wx.entity.WxPicReplyExample;
import com.wx.entity.WxResource;
import com.wx.entity.WxResourceExample;
import com.wx.entity.WxTemplatePush;
import com.wx.entity.WxTemplatePushExample;
import com.wx.entity.WxTextReply;
import com.wx.entity.WxVoiceReply;
import com.wx.flag.KeyWordType;
import com.wx.flag.MassMsgSendType;
import com.wx.flag.MassSendStatus;
import com.wx.service.SysWxTokenService;
import com.wx.service.SysWxuserService;
import com.wx.service.WxFansGroupService;
import com.wx.service.WxFansUserService;
import com.wx.service.WxMassMessageHisService;
import com.wx.service.WxMassMessageService;
import com.wx.service.WxMassSendResultService;
import com.wx.service.WxMulReplyService;
import com.wx.service.WxPicReplyService;
import com.wx.service.WxResourceService;
import com.wx.service.WxTemplatePushService;
import com.wx.service.WxTextReplyService;
import com.wx.service.WxVoiceReplyService;
import com.wx.util.DownloadImgUtil;
import com.wx.util.JsonResult;
import com.wx.util.JsonUtil;
import com.wx.vo.WxMassCronVO;
import com.zyht.bank.entity.WxTags;
import com.zyht.bank.service.WxTagsService;
import com.zyht.common.AbsManageBaseController;
import com.zyht.common.bean.PropertiesUtilBean.PropertiesUtils;
import com.zyht.common.bean.ThreadPoolWrapperBean;
import com.zyht.common.util.HttpUtils;
import com.zyht.common.util.Page;
import com.zyht.website.entity.SysUser;

import net.coobird.thumbnailator.Thumbnails;

@SuppressWarnings("unchecked")
@Controller
@RequestMapping("admin/mass")
public class WxMassMsgController extends AbsManageBaseController implements InitializingBean {

	private Logger logger = LoggerFactory.getLogger(getClass());
	@Resource
	private WxMassMessageService wxMassMessageService;
	@Resource
	private SysWxuserService sysWxuserService;
	@Resource
	private WxMulReplyService wxMulReplyService;
	@Resource
	private WxPicReplyService wxPicReplyService;
	@Resource
	private WxVoiceReplyService wxVoiceReplyService;
	@Resource
	private WxTextReplyService wxTextReplyService;
	@Resource
	private WxResourceService wxResourceService;
	@Resource
	private WxFansGroupService wxFansGroupService;
	@Resource
	private WxFansUserService wxFansUserService;
	@Resource
	private SysWxTokenService sysWxTokenService;
	@Resource
	private WxTagsService wxTagsService;
	@Resource
	private SchedulerFactoryBean schedulerFactoryBean;
	@Resource
	private WxMassMessageHisService wxMassMessageHisService;
	@Resource
	private WxTemplatePushService wxTemplatePushService;
	@Resource
	private WxMassSendResultService wxMassSendResultService;
	@Value("#{propertiesReader[session_user_key]}")
	private String sessionKey;

	@RequestMapping("totemplate")
	public String totemplate() {
		return "basic/mass/sendmsg";
	}

	@RequestMapping("gettemplate")
	public @ResponseBody String gettemplate(HttpServletRequest request) {
		List<WxTemplatePush> wxTemplates = wxTemplatePushService.findByExample(new WxTemplatePushExample());
		logger.info("模版数量为：" + wxTemplates.size());
		if (wxTemplates.size() > 0) {
			return JsonUtil.Object2Json(wxTemplates);
		} else {
			return "{\"errorcode\":\"0\"}";
		}
	}

	@RequestMapping("saveTemplate")
	public @ResponseBody String saveTemplate(String templates, HttpServletRequest request) {
		String ret = "";
		if (StringUtils.isEmpty(templates)) {
			ret = "{\"errorCode\":\"1\",\"errorMsg\":\"保存失败\"}";
			return ret;
		}
		Gson gson = new Gson();
		List<WxTemplatePush> tList = gson.fromJson(templates, new TypeToken<List<WxTemplatePush>>() {
		}.getType());
		for (WxTemplatePush wxTemplatePush : tList) {
			wxTemplatePushService.updateByPrimaryKeySelective(wxTemplatePush);
		}
		ret = "{\"errorCode\":\"0\",\"errorMsg\":\"保存成功\"}";
		return ret;
	}

	@RequestMapping("list")
	public ModelAndView list(Integer currentPage, HttpServletRequest request) {
		ModelAndView view = new ModelAndView("basic/mass/list");
		String pSize = PropertiesUtils.getConfig("paganation_page_size");
		int pageSize = Integer.valueOf(pSize);
		if (null == currentPage) {
			currentPage = 1;
		}
		Map<String, Object> params = new HashMap<>();
		params.put("wxid", getWxId(request));
		PageHelper.startPage(currentPage, pageSize);
		com.github.pagehelper.Page<WxMassAndSendResult> ghPage = (com.github.pagehelper.Page<WxMassAndSendResult>) this.wxMassMessageService
				.selectMassAndResultByExample(params);
		List<WxMassAndSendResult> list = ghPage.getResult();
		int total = (int) ghPage.getTotal();
		Page<WxMassAndSendResult> page = new Page<WxMassAndSendResult>(total, currentPage, pageSize);
		page.setRecordList(list);
		view.addObject("page", page);
		return view;
	}

	@RequestMapping("add")
	public String add(Model model, HttpServletRequest request) {
		// 获取用户的粉丝情况
		WxFansGroupExample example = new WxFansGroupExample();
		example.createCriteria().andWxidEqualTo(getWxId(request));
		List<WxFansGroup> groups = this.wxFansGroupService.selectByExample(example);
		model.addAttribute("groups", groups);
		return "basic/mass/add";
	}

	@RequestMapping("/fans")
	public void fansInfo(String nickname, Integer currentPage, PrintWriter out, HttpServletRequest request,
			HttpServletResponse response) {
		// 获取用户的粉丝情况
		Map<String, Object> params = new HashMap<String, Object>();
		if (!StringUtils.isEmpty(nickname)) {
			params.put("nickname", nickname);
		}

		int total = this.wxFansUserService.countEntityByExample(params);
		if (null == currentPage) {
			currentPage = 1;
		}
		String pSize = PropertiesUtils.getConfig("paganation_page_size");
		int pageSize = Integer.valueOf(pSize);

		PageHelper.startPage(currentPage, pageSize);
		List<WxFansUser> list = this.wxFansUserService.selectEntityByExample(params);
		Page<WxFansUser> page = new Page<WxFansUser>(total, currentPage, pageSize);
		page.setRecordList(list);
		String json = JsonUtil.Object2Json(page);
		writeJson(response, json);
	}

	@RequestMapping("persis")
	public String save(@ModelAttribute WxMassMessage bean, Model model, HttpServletRequest request,
			HttpServletResponse response) {
		bean.setCreateTime(new Date());
		bean.setWxid(getWxId(request));
		SysUser sysUser = getSessionUser(request);
		bean.setUid(sysUser.getId());
		Map<String, Object> data = new HashMap<String, Object>();
		data.put("msgType", bean.getMsgType());
		data.put("msgTitle", bean.getMsgTitle());
		data.put("msgId", bean.getMsgId());
		bean.setContent(JsonUtil.Object2Json(data));
		this.wxMassMessageService.insert(bean);

		model.addAttribute("redirect", "admin/mass/list");

		SysWxuser user = sysWxuserService.selectByWxid(getWxId(request));
		uploadResource(bean, user, request);

		return "message";
	}

	/**
	 * <b>作者:</b> zrb<br/>
	 * <b>修改时间：</b>2016年1月12日 - 下午3:39:16<br/>
	 * <b>功能说明：</b>同步素材<br/>
	 * 
	 * @param id
	 * @param request
	 * @param response
	 */
	@RequestMapping("syn")
	public void synPicResource(Integer id, HttpServletRequest request, HttpServletResponse response) {
		SysWxuser user = sysWxuserService.selectByWxid(getWxId(request));
		WxMassMessage mass = this.wxMassMessageService.selectByPrimaryKey(id);
		String content = mass.getContent();
		Map<String, Object> json = JSON.parseObject(content);
		Integer msgId = (Integer) json.get("msgId");
		Integer msgType = (Integer) json.get("msgType");
		mass.setMsgId(msgId);
		mass.setMsgType(msgType);
		// 先删除
		if (msgType == KeyWordType.TYPE_MUL_PIC.getValue()) {
			WxMulReply mul = wxMulReplyService.selectByPrimaryKey(msgId);
			String picIds = mul.getPicIds();
			String[] picArray = picIds.split(",");
			List<Integer> values = new ArrayList<Integer>();
			for (String str : picArray) {
				if (StringUtils.isEmpty(str)) {
					continue;
				}
				values.add(Integer.valueOf(str));
			}
			WxResourceExample wxResouceExample = new WxResourceExample();
			wxResouceExample.createCriteria().andRefIdIn(values).andRefTypeEqualTo(KeyWordType.TYPE_PIC.getValue());
			this.wxResourceService.deleteByPrimaryKey(wxResouceExample);

			wxResouceExample.clear();
			wxResouceExample.createCriteria().andRefIdEqualTo(msgId)
					.andRefTypeEqualTo(KeyWordType.TYPE_RES_MPIC.getValue());
			List<WxResource> list = this.wxResourceService.selectByExample(wxResouceExample);
			if (list.size() > 0) {
				WxResource resource = list.get(0);
				deleteResouce(user, resource.getMediaId());
				this.wxResourceService.deleteByPrimaryKey(resource.getId());
			}
		} else if (msgType == KeyWordType.TYPE_PIC.getValue()) {
			WxResourceExample wxResouceExample = new WxResourceExample();
			wxResouceExample.createCriteria().andRefIdEqualTo(msgId).andRefTypeEqualTo(KeyWordType.TYPE_PIC.getValue());
			this.wxResourceService.deleteByPrimaryKey(wxResouceExample);

			wxResouceExample.clear();
			wxResouceExample.createCriteria().andRefIdEqualTo(msgId)
					.andRefTypeEqualTo(KeyWordType.TYPE_RES_SPIC.getValue());
			List<WxResource> list = this.wxResourceService.selectByExample(wxResouceExample);
			if (list.size() > 0) {
				WxResource resource = list.get(0);
				deleteResouce(user, resource.getMediaId());
				this.wxResourceService.deleteByPrimaryKey(resource.getId());
			}
		}
		uploadResource(mass, user, request);
		writeJson(response, "{\"state\":200,\"msg\":\"同步成功\"}");
	}

	// 删除微信素材
	private void deleteResouce(SysWxuser user, String mediaId) {
		// 删除永久素材
		String token = sysWxTokenService.getAccessToken(user.getWxid(), user.getAppid(), user.getAppsecretd());
		Map<String, String> params = new HashMap<String, String>();
		params.put("media_id", mediaId);
		String jsonData = JSON.toJSONString(params);
		String delRes;
		try {
			delRes = HttpUtils.post(String.format(WxApi.DEL_MATERIAL, token), jsonData);
		} catch (IOException e) {
			e.printStackTrace();
			delRes = "素材删除失败：" + e.getMessage();
		}
		if (logger.isDebugEnabled()) {
			logger.debug("删除永久素材响应报文：" + delRes);
		}
	}

	// 上传素材
	private void uploadResource(WxMassMessage bean, SysWxuser user, HttpServletRequest request) {
		logger.info("启动微信资源上载....");
		// 获取用户的微信信息
		// 调用接口将资源文件上传
		int msgType = bean.getMsgType();
		int msgId = bean.getMsgId();
		String mediaType = "image";
		String token = sysWxTokenService.getAccessToken(user.getWxid(), user.getAppid(), user.getAppsecretd());

		if (msgType == KeyWordType.TYPE_MUL_PIC.getValue()) {
			logger.info("The type of article is multipart article");
			WxMulReply mul = wxMulReplyService.selectByPrimaryKey(msgId);
			String picIds = mul.getPicIds();
			String[] picArray = picIds.split(",");
			WxPicReplyExample example = new WxPicReplyExample();
			List<Integer> values = new ArrayList<Integer>();

			for (String str : picArray) {
				if (StringUtils.isEmpty(str)) {
					continue;
				}
				values.add(Integer.valueOf(str));
			}
			example.createCriteria().andIdIn(values);
			List<WxPicReply> pics = wxPicReplyService.selectByExample(example);
			for (WxPicReply pic : pics) {
				WxResourceExample wxResouceExample = new WxResourceExample();
				wxResouceExample.createCriteria().andRefIdEqualTo(pic.getId())
						.andRefTypeEqualTo(KeyWordType.TYPE_PIC.getValue());
				List<WxResource> list = wxResourceService.selectByExample(wxResouceExample);
				if (list.size() > 0) {
					continue;
				}

				String linkUrl = pic.getpImgHref();
				String uploadPath = request.getSession().getServletContext().getRealPath("/");
				String imagePath = uploadPath.concat(linkUrl);
				byte[] array = null;
				try {
					FileInputStream fis = new FileInputStream(imagePath);
					array = IOUtils.toByteArray(fis);
					if (null != fis) {
						fis.close();
					}
				} catch (FileNotFoundException e1) {
					e1.printStackTrace();
					logger.error("系统找不到指定文件【" + imagePath + "】");
				} catch (IOException e1) {
					e1.printStackTrace();
				}
				if (null == array) {
					logger.error("获取文件[" + linkUrl + "]失败！");
					return;
				}
				String fileName = StringUtils.getFilename(linkUrl);

				String uri = WxApi.MATERIAL_UPLOAD;
				uri = String.format(uri, token);
				HttpClient client = new HttpClient();
				HttpConnectionManagerParams params = client.getHttpConnectionManager().getParams();
				params.setConnectionTimeout(5000);
				params.setSoTimeout(5000);
				client.getHttpConnectionManager().setParams(params);
				PostMethod post = new PostMethod(uri);
				try {
					ByteArrayPartSource ps = new ByteArrayPartSource(fileName, array);
					Part[] parts = { new FilePart("media", ps), new StringPart("access_token", token),
							new StringPart("type", mediaType) };
					MultipartRequestEntity multipartEntity = new MultipartRequestEntity(parts, post.getParams());
					post.setRequestEntity(multipartEntity);
					int code = client.executeMethod(post);
					if (code == HttpStatus.SC_OK) {
						String postResponse = post.getResponseBodyAsString();
						logger.info("微信上传素材信息是：" + postResponse);
						Map<String, String> map = (Map<String, String>) JsonUtil.str2map(postResponse,
								new TypeReference<Map<String, String>>() {
								});
						String mediaId = map.get("media_id");
						String errcode = map.get("errcode");
						if (!StringUtils.isEmpty(errcode)) {
							logger.info("微信素材[" + linkUrl + "]上传异常，errcode is -->" + errcode);
							continue;
						}
						WxResourceExample wxResourceExample = new WxResourceExample();
						wxResourceExample.createCriteria().andRefIdEqualTo(pic.getId())
								.andRefTypeEqualTo(KeyWordType.TYPE_PIC.getValue());
						List<WxResource> wxResources = wxResourceService.selectByExample(wxResourceExample);
						if (wxResources.size() > 0) {
							wxResourceService.deleteByPrimaryKey(wxResources.get(0).getId());
						}
						String wxImageUrl = map.get("url");
						WxResource resource = new WxResource();
						resource.setRefId(pic.getId());
						resource.setRefType(KeyWordType.TYPE_PIC.getValue());
						resource.setMediaId(mediaId);
						resource.setWxImageUrl(wxImageUrl);
						wxResourceService.insert(resource);
					} else {
						logger.info("微信素材[" + linkUrl + "]上传异常，返回响应码是【" + code + "】");
					}
				} catch (HttpException e) {
					logger.error("微信Http上传素材请求失败" + e.getMessage());
					continue;
				} catch (IOException e) {
					logger.error("微信Http上传素材请求IO失败" + e.getMessage());
					continue;
				}
			}
		} else if (msgType == KeyWordType.TYPE_PIC.getValue()) {
			logger.info("The type of article is single article");
			WxPicReply pic = wxPicReplyService.selectByPrimaryKey(msgId);

			WxResourceExample wxResouceExample = new WxResourceExample();
			wxResouceExample.createCriteria().andRefIdEqualTo(pic.getId())
					.andRefTypeEqualTo(KeyWordType.TYPE_PIC.getValue());
			List<WxResource> list = wxResourceService.selectByExample(wxResouceExample);
			if (list.size() > 0) {
				return;
			}

			String linkUrl = pic.getpImgHref();
			String uploadPath = request.getSession().getServletContext().getRealPath("/");
			String imagePath = uploadPath.concat(linkUrl);
			byte[] array = null;
			try {
				FileInputStream fis = new FileInputStream(imagePath);
				array = IOUtils.toByteArray(fis);
				if (null != fis) {
					fis.close();
				}
			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
				logger.error("系统找不到指定文件【" + imagePath + "】");
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			if (null == array) {
				logger.error("获取文件[" + linkUrl + "]失败！");
				return;
			}
			int len = array.length;
			if (1024 * 1024 * 1 < len) {
				try {
					String srcPath = getTempFilePath("temp.jpg");
					FileOutputStream fos = new FileOutputStream(srcPath);
					fos.write(array);
					if (null != fos) {
						fos.close();
					}
					double scale = (1024 * 1024 * 1.0d) / (len + 100d);
					String tempPath = getTempFilePath("temp.jpg");
					File outFile = new File(tempPath);
					File srcFile = new File(srcPath);
					Thumbnails.of(srcFile).scale(scale).outputQuality(1d).toFile(outFile);
					InputStream fileIs = new FileInputStream(outFile);
					array = IOUtils.toByteArray(fileIs);
					if (null != fileIs) {
						fileIs.close();
						fileIs = null;
					}
					if (srcFile.exists()) {
						srcFile.delete();
					}
					if (outFile.exists()) {
						outFile.delete();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			String fileName = StringUtils.getFilename(linkUrl);

			String uri = WxApi.MATERIAL_UPLOAD;
			uri = String.format(uri, token);
			HttpClient client = new HttpClient();
			HttpConnectionManagerParams params = client.getHttpConnectionManager().getParams();
			params.setConnectionTimeout(5000);
			params.setSoTimeout(5000);
			client.getHttpConnectionManager().setParams(params);
			PostMethod post = new PostMethod(uri);
			try {
				ByteArrayPartSource ps = new ByteArrayPartSource(fileName, array);
				Part[] parts = { new FilePart("media", ps), new StringPart("access_token", token),
						new StringPart("type", mediaType) };
				MultipartRequestEntity multipartEntity = new MultipartRequestEntity(parts, post.getParams());
				post.setRequestEntity(multipartEntity);
				int code = client.executeMethod(post);
				logger.info("微信上传素材请求状态码是：" + code);
				if (code == HttpStatus.SC_OK) {
					String postResponse = post.getResponseBodyAsString();
					logger.info("微信上传素材信息是：" + postResponse);
					Map<String, String> map = (Map<String, String>) JsonUtil.str2map(postResponse,
							new TypeReference<Map<String, String>>() {
							});
					String errcode = map.get("errcode");
					if (!StringUtils.isEmpty(errcode)) {
						logger.info("微信素材[" + linkUrl + "]上传异常，errcode is -->" + errcode);
						return;
					}
					WxResourceExample wxResourceExample = new WxResourceExample();
					wxResourceExample.createCriteria().andRefIdEqualTo(pic.getId())
							.andRefTypeEqualTo(KeyWordType.TYPE_PIC.getValue());
					List<WxResource> wxResources = wxResourceService.selectByExample(wxResourceExample);
					if (wxResources.size() > 0) {
						wxResourceService.deleteByPrimaryKey(wxResources.get(0).getId());
					}
					String mediaId = map.get("media_id");
					String url = map.get("url");
					WxResource resource = new WxResource();
					resource.setRefId(pic.getId());
					resource.setRefType(KeyWordType.TYPE_PIC.getValue());
					resource.setMediaId(mediaId);
					resource.setWxImageUrl(url);
					wxResourceService.insert(resource);
				} else {
					logger.info("微信素材[" + linkUrl + "]上传异常，返回响应码是【" + code + "】");
				}
			} catch (HttpException e) {
				logger.error("微信Http上传素材请求失败" + e.getMessage());
			} catch (IOException e) {
				logger.error("微信Http上传素材请求IO失败" + e.getMessage());
			}
		} else if (msgType == KeyWordType.TYPE_RADIO.getValue())

		{
			return;
		}

	}

	@RequestMapping("del")
	public String deleteById(Integer flag, Model model, HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		if (null == flag)
			flag = 0;
		WxMassMessageExample example = new WxMassMessageExample();
		example.createCriteria().andWxidEqualTo(getWxId(request)).andIdEqualTo(flag);
		WxMassMessage message = this.wxMassMessageService.selectByPrimaryKey(flag);
		String name = "mass_message_" + message.getId();
		String group = "msss_massege";
		JobKey jobKey = JobKey.jobKey(name, group);
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		boolean isExist = false;
		try {
			isExist = scheduler.checkExists(jobKey);
		} catch (SchedulerException e) {
			logger.info("检查定时任务失败……");
			e.printStackTrace();
		}
		if (isExist) {
			model.addAttribute("msg", "此群发消息已经设置定时发送，不能删除！");
			model.addAttribute("redirect", "admin/mass/list");
		} else {
			this.wxMassMessageService.deleteByPrimaryKey(example);
			String mediaId = message.getMdiaId();
			boolean needDel = true;
			if (!StringUtils.isEmpty(mediaId)) {
				needDel = false;
				// 删除永久素材
				SysWxuser user = sysWxuserService.selectByWxid(message.getWxid());
				String token = sysWxTokenService.getAccessToken(user.getWxid(), user.getAppid(), user.getAppsecretd());
				Map<String, String> params = new HashMap<String, String>();
				params.put("media_id", mediaId);
				String jsonData = JSON.toJSONString(params);
				String delRes = HttpUtils.post(String.format(WxApi.DEL_MATERIAL, token), jsonData);
				logger.debug("删除永久素材响应报文：" + delRes);
			}

			Map<String, Object> content = (Map<String, Object>) JsonUtil.str2map(message.getContent(),
					new TypeReference<Map<String, Object>>() {
					});
			Integer msgId = (Integer) content.get("msgId");
			Integer msgType = (Integer) content.get("msgType");
			if (msgType == KeyWordType.TYPE_MUL_PIC.getValue() || msgType == KeyWordType.TYPE_PIC.getValue()) {
				WxResourceExample wResouceExample = new WxResourceExample();
				if (msgType == KeyWordType.TYPE_MUL_PIC.getValue()) {
					wResouceExample.createCriteria().andRefIdEqualTo(msgId)
							.andRefTypeEqualTo(KeyWordType.TYPE_RES_MPIC.getValue());
				} else if (msgType == KeyWordType.TYPE_PIC.getValue()) {
					wResouceExample.createCriteria().andRefIdEqualTo(msgId)
							.andRefTypeEqualTo(KeyWordType.TYPE_RES_SPIC.getValue());
				}
				List<WxResource> delList = this.wxResourceService.selectByExample(wResouceExample);
				if (delList.size() > 0) {
					WxResource res = delList.get(0);
					if (needDel) {
						String mid = res.getMediaId();
						SysWxuser user = sysWxuserService.selectByWxid(message.getWxid());
						String token = sysWxTokenService.getAccessToken(user.getWxid(), user.getAppid(),
								user.getAppsecretd());
						Map<String, String> params = new HashMap<String, String>();
						params.put("media_id", mid);
						String delRes = HttpUtils.post(String.format(WxApi.DEL_MATERIAL, token),
								JSON.toJSONString(params));
						logger.debug("删除永久素材响应报文：" + delRes);
					}
					this.wxResourceService.deleteByPrimaryKey(wResouceExample);
				}
			}

			model.addAttribute("msg", "删除成功");
			model.addAttribute("redirect", "admin/mass/list");
		}
		return "message";
	}

	@RequestMapping("msg")
	public void sendMessage(Integer id, String tagId, PrintWriter out, Model model, HttpServletRequest request,
			HttpServletResponse response) {
		String wxid = getWxId(request);
		String basePath = getServerPath(request);
		String json = doSend(id, false, wxid, basePath);
		writeJson(response, json);
	}

	/**
	 * @author: data-zrb 修改时间：2015年12月11日 - 下午4:21:15<br/>
	 *          功能说明：获取服务地址<br/>
	 * @param request
	 * @return
	 */
	private String getServerPath(HttpServletRequest request) {

		int port = request.getServerPort();
		String basePath = request.getScheme() + "://" + request.getServerName();
		if (port != 80) {
			basePath = basePath + ":" + port;
		}
		basePath += request.getContextPath() + "/";
		return basePath;
	}

	/*
	 * 查询群发消息状态
	 */
	private void getMassSendStatusInfo(String token, String responseStr, Integer massId, String wxid) {
		Map<String, String> map = (Map<String, String>) JsonUtil.str2map(responseStr,
				new TypeReference<Map<String, String>>() {
				});
		String msgid = map.get("msg_id");
		// 记录msg_id
		WxMassSendResult entity = new WxMassSendResult();
		entity.setMsgId(msgid);
		entity.setMassId(massId);
		entity.setToUserName(wxid);
		this.wxMassSendResultService.addOne(entity);

		Runnable statusRun = () -> {
			String queryUrl = String.format(WxApi.MASS_STATUS_QUERY, token);
			String jsonData = "{\"msg_id\":\"" + msgid + "\"}";
			try {
				String queryResult = HttpUtils.post(queryUrl, jsonData);
				logger.info("查询群发消息查询状态返回结果信息是：" + queryResult);
			} catch (Exception e) {
				e.printStackTrace();
				logger.info("查询群发消息查询状态返回结果信息异常：" + e.getMessage());
			}
		};
		ThreadPoolWrapperBean.getThreadPool().putThread(statusRun);
	}

	@RequestMapping("task")
	public void setQuartzTask(@ModelAttribute WxMassCronVO mass, PrintWriter out, HttpServletRequest request,
			HttpServletResponse response) throws SchedulerException {
		// 获取任务调度bean
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		// 产生task
		String name = "mass_message_" + mass.getId();
		String group = "msss_massege";
		// 设置CronExpression
		StringBuffer cronExpression = new StringBuffer();
		cronExpression.append(mass.getSecond() + " ");
		cronExpression.append(mass.getMinute() + " ");
		cronExpression.append(mass.getHour() + " ");
		cronExpression.append(mass.getDay() + " ");
		cronExpression.append(mass.getMonth() + " ");
		cronExpression.append("? ");
		cronExpression.append(mass.getYear());
		TriggerKey triggerKey = new TriggerKey(name, group);
		CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
		if (null == cronTrigger) {
			JobDetail jobDetail = JobBuilder.newJob(SentMassJob.class).withIdentity(name, group).build();
			jobDetail.getJobDataMap().put("name", name);
			jobDetail.getJobDataMap().put("group", group);
			jobDetail.getJobDataMap().put("id", mass.getId());
			String wxid = getWxId(request);
			jobDetail.getJobDataMap().put("wxid", wxid);
			String serverPath = getServerPath(request);
			jobDetail.getJobDataMap().put("serverPath", serverPath);
			jobDetail.getJobDataMap().put("wxMassMsgController", this);
			jobDetail.getJobDataMap().put("schedulerFactoryBean", schedulerFactoryBean);
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression.toString());
			cronTrigger = TriggerBuilder.newTrigger().withIdentity(name, group).withSchedule(scheduleBuilder).build();
			try {
				scheduler.scheduleJob(jobDetail, cronTrigger);
			} catch (Exception e) {
				logger.warn(e.getMessage());
				boolean flag = scheduler.checkExists(triggerKey);
				if (flag) {
					JobKey key = new JobKey(name, group);
					scheduler.deleteJob(key);
				}
			}
		} else {
			this.writeJson(response, "{\"message\":\"任务已存在\"}");
			return;
		}

		List<String> groups = scheduler.getJobGroupNames();
		logger.info("现在已有的定制任务组名是：" + JsonUtil.Object2Json(groups));

		WxMassMessage record = new WxMassMessage();
		record.setId(mass.getId());
		record.setIsInterval("1");
		record.setCronExpression(cronExpression.toString());
		this.wxMassMessageService.updateByPrimaryKey(record);
		this.writeJson(response, "{\"message\":\"操作成功\"}");
	}

	/**
	 * @author: data-zrb 修改时间：2015年10月10日 - 下午5:21:39<br/>
	 *          功能说明：controller初始化执行预处理操作<br/>
	 * @throws SchedulerException
	 */
	// @PostConstruct
	public void init() throws SchedulerException {
		WxMassMessageExample example = new WxMassMessageExample();
		example.createCriteria().andSendStatusIsNull().andIsIntervalEqualTo("1").andCronExpressionIsNotNull();
		List<WxMassMessage> list = this.wxMassMessageService.selectByExample(example);
		// 获取任务调度bean
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		for (WxMassMessage message : list) {
			// 产生task
			String name = "mass_message_" + message.getId().toString();
			String group = "msss_massege";
			// 设置CronExpression
			TriggerKey triggerKey = new TriggerKey(name, group);
			CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
			if (null == cronTrigger) {
				JobDetail jobDetail = JobBuilder.newJob(SentMassJob.class).withIdentity(name, group).build();
				jobDetail.getJobDataMap().put("name", name);
				jobDetail.getJobDataMap().put("group", group);
				jobDetail.getJobDataMap().put("id", message.getId().toString());
				jobDetail.getJobDataMap().put("wxMassMsgController", this);
				jobDetail.getJobDataMap().put("schedulerFactoryBean", schedulerFactoryBean);
				CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(message.getCronExpression());
				cronTrigger = TriggerBuilder.newTrigger().withIdentity(name, group).withSchedule(scheduleBuilder)
						.build();
				try {
					scheduler.scheduleJob(jobDetail, cronTrigger);
				} catch (Exception e) {
					logger.warn(e.getMessage());
					boolean flag = scheduler.checkExists(triggerKey);
					if (flag) {
						JobKey key = new JobKey(name, group);
						scheduler.deleteJob(key);
					}
					continue;
				}
			}
		}
		List<String> groups = scheduler.getJobGroupNames();
		logger.info("现在已有的定制任务组名是：" + JsonUtil.Object2Json(groups));
	}

	/**
	 * @author: data-zrb 修改时间：2015年12月11日 - 下午4:18:58<br/>
	 *          功能说明：定时任务执行方法<br/>
	 * @param id
	 * @param wxid
	 * @param serverPath
	 * @return
	 */
	public String doTaskSent(Integer id, String wxid, String serverPath) {
		return doSend(id, true, wxid, serverPath);
	}

	// 预处理大字符串内容
	private String preDealContent(String content, SysWxuser user) {
		content = content.replace("\"", "'");
		// 解析出content中的img
		String regex = "<img[^>]+src\\s*=\\s*['\"]([^'\"]+)['\"][^>]*>";
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(content);
		Pattern patternSrc = Pattern.compile("src\\s*=\\s*['\"]([^'\"]+)['\"]");
		StringBuffer sb = new StringBuffer();
		while (matcher.find()) {
			String imgUrl = matcher.group(1);
			if (StringUtils.isEmpty(imgUrl))
				continue;
			// 解析imgUrl
			if (imgUrl.startsWith("http")) {
				// 绝对路径
				if (imgUrl.indexOf("http://mmbiz.qpic.cn/mmbiz") >= 0) {
					// 微信的地址直接跳过
					continue;
				}
			} else if (imgUrl.startsWith("/")) {
				// 相对路径
				// do nothing
			} else {
				// 添加 "/"
				imgUrl = "/" + imgUrl;
				// 错误路径，不做筛选，微信会自动清除
			}
			// 先要下载
			byte[] array = DownloadImgUtil.fetchStream(imgUrl);
			if (null == array) {
				logger.error("下载远程文件【" + imgUrl + "】失败");
				continue;
			}

			String fileName = StringUtils.getFilename(imgUrl);

			String uri = WxApi.MASS_UPLOADIMG;
			String token = sysWxTokenService.getAccessToken(user.getWxid(), user.getAppid(), user.getAppsecretd());
			uri = String.format(uri, token);
			HttpClient client = new HttpClient();
			HttpConnectionManagerParams params = client.getHttpConnectionManager().getParams();
			params.setConnectionTimeout(5000);
			params.setSoTimeout(5000);
			client.getHttpConnectionManager().setParams(params);
			PostMethod post = new PostMethod(uri);
			try {
				ByteArrayPartSource ps = new ByteArrayPartSource(fileName, array);
				Part[] parts = { new FilePart("media", ps) };
				MultipartRequestEntity multipartEntity = new MultipartRequestEntity(parts, post.getParams());
				post.setRequestEntity(multipartEntity);
				int code = client.executeMethod(post);
				logger.info("微信上传素材请求状态码是：" + code);
				if (code == HttpStatus.SC_OK) {
					String postResponse = post.getResponseBodyAsString();
					logger.info("微信上传素材信息是：" + postResponse);
					Map<String, Object> map = (Map<String, Object>) JsonUtil.str2map(postResponse,
							new TypeReference<Map<String, Object>>() {
							});
					Integer errcode = (Integer) map.get("errcode");
					if (null != errcode) {
						logger.warn("上传图文详情页的图片异常：" + errcode.intValue());
					} else {
						// 记录返回的微信地址
						String url = map.get("url").toString();
						// 修改原文本内容中的图片地址
						Matcher ma = patternSrc.matcher(matcher.group(0));
						StringBuffer s = new StringBuffer();
						if (ma.find()) {
							ma.appendReplacement(s, "src='" + url + "'");
						}
						ma.appendTail(s);
						matcher.appendReplacement(sb, s.toString());
					}
				} else {
					logger.info("微信素材[" + imgUrl + "]上传异常，返回响应码是【" + code + "】");
				}
			} catch (HttpException e) {
				logger.error("微信Http上传素材请求失败" + e.getMessage());
			} catch (IOException e) {
				logger.error("微信Http上传素材请求IO失败" + e.getMessage());
			}
		}
		matcher.appendTail(sb);
		// 上传到微信
		return sb.toString();
	}

	// 执行发送操作
	private String doSend(Integer id, boolean isTask, String wxid, String basePath, boolean isPreview,
			Map<String, Object> previewData) {
		if (null == id)
			id = 0;
		WxMassMessage entity = wxMassMessageService.selectByPrimaryKey(id);

		if (null == entity) {
			logger.info("群发消息[id is " + id + "]不存在");
			String json = JsonUtil.Object2Json(JsonResult.messageJson(false, "非法参数"));
			if (!isTask) {
				return json;
			}
			return null;
		}

		String tagId = entity.getGroupInfos();

		SysWxuser user = null;
		if (isTask) {
			WxMassMessage message = this.wxMassMessageService.selectByPrimaryKey(id);
			user = sysWxuserService.selectByWxid(message.getWxid());
		} else {
			user = sysWxuserService.selectByWxid(wxid);
		}
		String token = sysWxTokenService.getAccessToken(user.getWxid(), user.getAppid(), user.getAppsecretd());
		Map<String, Object> content = (Map<String, Object>) JsonUtil.str2map(entity.getContent(),
				new TypeReference<Map<String, Object>>() {
				});
		entity.setMsgId((Integer) content.get("msgId"));
		entity.setMsgType((Integer) content.get("msgType"));
		Integer msgType = entity.getMsgType();
		int sendType = entity.getSendType().intValue();
		if (msgType == KeyWordType.TYPE_MUL_PIC.getValue() || msgType == KeyWordType.TYPE_PIC.getValue()) {
			int refId = 0;
			// 如果图文或多图文已经上传，就不需要再次上传了
			// 2015年12月22日，添加直接获取图文素材，而不需要重新上传，以节省微信中的空间
			boolean isSimple = true;
			WxResourceExample resExample = new WxResourceExample();
			if (msgType == KeyWordType.TYPE_PIC.getValue()) {
				resExample.createCriteria().andRefTypeEqualTo(KeyWordType.TYPE_RES_SPIC.getValue())
						.andRefIdEqualTo(entity.getMsgId());
			} else {
				resExample.createCriteria().andRefTypeEqualTo(KeyWordType.TYPE_RES_MPIC.getValue())
						.andRefIdEqualTo(entity.getMsgId());
				isSimple = false;
			}
			List<WxResource> resList = this.wxResourceService.selectByExample(resExample);
			String mid = null;
			if (resList.size() > 0 && !StringUtils.isEmpty(mid = resList.get(0).getMediaId())) {
				entity.setMdiaId(mid);
			} else {
				if (null == entity.getSendStatus()
						|| entity.getSendStatus().intValue() != MassSendStatus.STATUS_SENT.intValue()) {
					List<WxPicReply> pics = new ArrayList<WxPicReply>();
					List<Map<String, String>> arrays = new ArrayList<Map<String, String>>();
					if (msgType.intValue() == KeyWordType.TYPE_MUL_PIC.getValue()) {
						WxMulReply reply = wxMulReplyService.selectByPrimaryKey(entity.getMsgId());
						refId = reply.getId();
						String[] ids = reply.getPicIds().split(",");

						for (String str : ids) {
							if (StringUtils.isEmpty(str)) {
								continue;
							}
							WxPicReply pic = wxPicReplyService.selectByPrimaryKey(Integer.valueOf(str));
							pics.add(pic);
						}
					} else if (msgType.intValue() == KeyWordType.TYPE_PIC.getValue()) {
						WxPicReply reply = wxPicReplyService.selectByPrimaryKey(entity.getMsgId());
						refId = reply.getId();
						pics = new ArrayList<WxPicReply>();
						pics.add(reply);
					}

					for (WxPicReply pic : pics) {
						WxResourceExample wxResourceExample = new WxResourceExample();
						wxResourceExample.createCriteria().andRefIdEqualTo(pic.getId())
								.andRefTypeEqualTo(KeyWordType.TYPE_PIC.getValue());
						List<WxResource> resources = wxResourceService.selectByExample(wxResourceExample);
						WxResource wxResource = new WxResource();
						if (resources.size() > 0) {
							wxResource = resources.get(0);
						} else {
							continue;
						}
						Map<String, String> article = new HashMap<String, String>();
						article.put("thumb_media_id", wxResource.getMediaId());
						article.put("title", pic.getTitle());
						String detailContent = pic.getDetailContent();
						if (null == detailContent || "".equals(detailContent.replace(" ", ""))) {
							detailContent = "暂无文章内容！";
						}
						detailContent = preDealContent(detailContent, user);
						article.put("content", detailContent);
						if (!StringUtils.isEmpty(pic.getArticleUrl())) {
							article.put("content_source_url", pic.getArticleUrl());
						} else {
							article.put("content_source_url", basePath + "pic/detail?id=" + pic.getId());
						}
						if (!StringUtils.isEmpty(pic.getpSummary())) {
							article.put("digest", pic.getpSummary());
						}
						if (pic.getIsShow() == 1) {
							article.put("show_cover_pic", "1");
						} else {
							article.put("show_cover_pic", "0");
						}
						arrays.add(article);
					}

					// 上传图文素材
					HttpClient client = new HttpClient();
					HttpConnectionManagerParams params = client.getHttpConnectionManager().getParams();
					params.setConnectionTimeout(5000);
					params.setSoTimeout(5000);
					client.getHttpConnectionManager().setParams(params);
					String fixedNewsUrl = String.format(WxApi.MATERIAL_ADD_NEWS, token);
					PostMethod post2 = new PostMethod(fixedNewsUrl);
					Map<String, Object> articles = new HashMap<String, Object>();
					articles.put("articles", arrays);
					Gson gson = new GsonBuilder().disableHtmlEscaping().create();
					String json = gson.toJson(articles);
					// logger.info("上传永久素材json字符串是[微信消息群发]：" + json);
					articles = null;
					try {
						StringRequestEntity strRequest = new StringRequestEntity(json, "application/json", "utf-8");
						post2.setRequestEntity(strRequest);
						int code = client.executeMethod(post2);
						if (code == HttpStatus.SC_OK) {
							String postResponse = post2.getResponseBodyAsString();
							logger.info("微信上传素材信息是：" + postResponse);
							Map<String, String> map = (Map<String, String>) JsonUtil.str2map(postResponse,
									new TypeReference<Map<String, String>>() {
									});
							String mediaId = map.get("media_id");
							String errcode = map.get("errcode");
							if (!StringUtils.isEmpty(errcode)) {
								String strJson = JsonUtil.Object2Json(JsonResult.messageJson(false, "微信上传素材接口异常"));
								if (isPreview) {
									Map<String, Object> resultJson = new HashMap<>();
									resultJson.put("state", 400);
									resultJson.put("msg", map.get("errmsg"));
									return JSON.toJSONString(resultJson);
								}
								if (!isTask) {
									return strJson;
								}
								return null;
							}
							entity.setMdiaId(mediaId);

							// 如果图文上传成功，保存mediaid，避免重复上传
							WxResource saveResource = new WxResource();
							saveResource.setMediaId(mediaId);
							saveResource.setRefId(refId);
							if (isSimple) {
								saveResource.setRefType(KeyWordType.TYPE_RES_SPIC.getValue());
							} else {
								saveResource.setRefType(KeyWordType.TYPE_RES_MPIC.getValue());
							}
							this.wxResourceService.insert(saveResource);
						}
					} catch (UnsupportedEncodingException e) {
						e.printStackTrace();
					} catch (HttpException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
			// 如果是预览
			if (isPreview) {
				String msgtype = "mpnews";
				String contentName = "media_id";
				Map<String, Object> resultJson = doPreview(previewData, entity.getMdiaId(), token, msgtype,
						contentName);
				return JSON.toJSONString(resultJson);
			}
			// 如果有素材直接发送
			String sendJson = "{\"filter\":{\"is_to_all\":false,\"tag_id\":" + tagId + "}, \"mpnews\":{\"media_id\":\""
					+ entity.getMdiaId() + "\" }, \"msgtype\":\"mpnews\",\"send_ignore_reprint\":\"1\"}";
			String sendUrl = String.format(WxApi.SEND_BY_GROUP, token);
			try {
				String responseStr = HttpUtils.post(sendUrl, sendJson);
				getMassSendStatusInfo(token, responseStr, id, wxid);
				// 保存记录
				addMassHis(entity.getMdiaId(), user.getWxid(), msgType, refId, null);
			} catch (Exception e) {
				e.printStackTrace();
				logger.error("用户【" + user.getId() + "," + user.getAppid() + "】http群发消息异常：" + e.getMessage());
			}

		} else if (msgType.intValue() == KeyWordType.TYPE_RADIO.getValue()) {
			WxVoiceReply reply = wxVoiceReplyService.selectByPrimaryKey(entity.getMsgId());
			WxResourceExample resource = new WxResourceExample();
			resource.createCriteria().andRefIdEqualTo(reply.getId()).andRefTypeEqualTo(msgType);
			List<WxResource> resources = wxResourceService.selectByExample(resource);
			WxResource wxResource = new WxResource();
			if (resources.size() > 0) {
				wxResource = resources.get(0);
			} else {
				String json = JsonUtil.Object2Json(JsonResult.messageJson(false, "素材缺失"));
				if (!isTask) {
					return json;
				}
				return null;
			}

			// 如果是预览
			if (isPreview) {
				String msgtype = "voice";
				String contentName = "media_id";
				Map<String, Object> resultJson = doPreview(previewData, wxResource.getMediaId(), token, msgtype,
						contentName);
				return JSON.toJSONString(resultJson);
			}

			if (MassMsgSendType.TYPE_SEND_GROUP.intValue() == sendType) {
				String sendJson = "{\"filter\":{\"is_to_all\":false,\"tag_id\":" + tagId
						+ "},\"voice\":{\"media_id\":\"" + wxResource.getMediaId() + "\"},\"msgtype\":\"voice\"}";

				String sendUrl = String.format(WxApi.SEND_BY_GROUP, token);
				try {
					String responseStr = HttpUtils.post(sendUrl, sendJson);
					logger.info("群发消息响应正文是：" + responseStr);
					getMassSendStatusInfo(token, responseStr, id, wxid);
					// 保存记录
					addMassHis(wxResource.getMediaId(), user.getWxid(), msgType, reply.getId(), reply.getLinkUrl());
				} catch (Exception e) {
					e.printStackTrace();
					logger.error("用户【" + user.getId() + "," + user.getAppid() + "】http群发消息异常：" + e.getMessage());
				}
			}
			entity.setSendStatus((byte) MassSendStatus.STATUS_SENT.intValue());
			entity.setSendTime(new Date());
			wxMassMessageService.updateByPrimaryKey(entity);
		} else if (msgType.intValue() == KeyWordType.TYPE_TXT.getValue()) {
			WxTextReply reply = wxTextReplyService.selectByPrimaryKey(entity.getMsgId());

			// 如果是预览
			if (isPreview) {
				String msgtype = "text";
				String contentName = "content";
				Map<String, Object> resultJson = doPreview(previewData, reply.getContent(), token, msgtype,
						contentName);
				return JSON.toJSONString(resultJson);
			}

			if (MassMsgSendType.TYPE_SEND_GROUP.intValue() == sendType) {
				String sendJson = "{\"filter\":{\"is_to_all\":false,\"tag_id\":" + tagId + "},\"text\":{\"content\":\""
						+ reply.getContent() + "\"},\"msgtype\":\"text\"}";

				String sendUrl = String.format(WxApi.SEND_BY_GROUP, token);
				try {
					String responseStr = HttpUtils.post(sendUrl, sendJson);
					logger.info("群发消息响应正文是：" + responseStr);
					getMassSendStatusInfo(token, responseStr, id, wxid);
					// 保存记录
					addMassHis(reply.getContent(), user.getWxid(), msgType, reply.getId(), null);
				} catch (Exception e) {
					e.printStackTrace();
					logger.error("用户【" + user.getId() + "," + user.getAppid() + "】http群发消息异常：" + e.getMessage());
				}
			}
		}
		entity.setSendStatus((byte) MassSendStatus.STATUS_SENT.intValue());
		entity.setSendTime(new Date());
		wxMassMessageService.updateByPrimaryKey(entity);
		return JsonUtil.Object2Json(JsonResult.messageJson(true, "Operation success"));
	}

	// 实现预览
	private Map<String, Object> doPreview(Map<String, Object> previewData, String mediaId, String token, String msgtype,
			String contentName) {

		Map<String, Object> resultJson = new HashMap<>();
		if (null != previewData) {
			Integer dataType = (Integer) previewData.get("type");
			String dataCode = (String) previewData.get("code");
			String toType = null;
			if (0 == dataType) {
				// 微信号
				toType = "towxname";
			} else if (1 == dataType) {
				// openid
				toType = "touser";
			}
			String postJson = "{\"" + toType + "\":\"" + dataCode + "\",\"" + msgtype + "\":{\"" + contentName + "\":\""
					+ mediaId + "\"},\"msgtype\":\"" + msgtype + "\"}";
			String postUrl = String.format(WxApi.MASS_SEND_PREVIEW, token);
			try {
				String responseStr = HttpUtils.post(postUrl, postJson);
				Map<String, Object> map = (Map<String, Object>) JsonUtil.str2map(responseStr,
						new TypeReference<Map<String, Object>>() {
						});
				Integer errcode = (Integer) map.get("errcode");
				if (0 != errcode) {
					String errmsg = (String) map.get("errmsg");
					throw new Exception(errmsg);
				}
				resultJson.put("state", 200);
				resultJson.put("msg", "预览成功");
			} catch (Exception e) {
				e.printStackTrace();
				// error
				resultJson.put("state", 400);
				resultJson.put("msg", e.getMessage());
			}
		} else {
			resultJson.put("state", 400);
			resultJson.put("msg", "缺少参数");
		}
		return resultJson;
	}

	// 执行群发消息
	private String doSend(Integer id, boolean isTask, String wxid, String basePath) {
		return doSend(id, isTask, wxid, basePath, false, null);
	}

	// 保存群发历史
	private void addMassHis(String mediaId, String wxid, int type, Integer refId, String filePath) {
		WxMassMessageHis his = new WxMassMessageHis();
		his.setMessageType(type + "");
		his.setWxid(wxid);
		his.setMessageContent(mediaId);
		his.setSendTime(new Date());
		his.setRefId(refId);
		his.setFilePath(filePath);
		wxMassMessageHisService.addOne(his);
	}

	/**
	 * @author: data-zrb 修改时间：2015年12月22日 - 下午3:39:38<br/>
	 *          功能说明：实现预览<br/>
	 * @param id
	 * @param response
	 */
	@RequestMapping("preview")
	public void preview(Integer id, Integer type, String code, HttpServletRequest request,
			HttpServletResponse response) {
		String json = null;
		if (id != null) {
			Map<String, Object> data = new HashMap<>();
			data.put("type", type);
			data.put("code", code);
			String basePath = getServerPath(request);
			json = doSend(id, false, getWxId(request), basePath, true, data);
		} else {
			Map<String, Object> result = new HashMap<>();
			result.put("state", 400);
			result.put("msg", "非法参数");
			json = JSON.toJSONString(result);
		}
		writeJson(response, json);
	}

	@RequestMapping("/tag")
	public void tagInfo(String nickname, Integer currentPage, PrintWriter out, HttpServletRequest request,
			HttpServletResponse response) {
		String pSize = PropertiesUtils.getConfig("paganation_page_size");
		int pageSize = Integer.valueOf(pSize);
		PageHelper.startPage(currentPage, pageSize);
		com.github.pagehelper.Page<WxTags> tags = (com.github.pagehelper.Page<WxTags>) wxTagsService.list(null);
		Page<WxTags> page = new Page<WxTags>((int) tags.getTotal(), currentPage, pageSize);
		page.setRecordList(tags.getResult());

		String json = JsonUtil.Object2Json(page);
		writeJson(response, json);
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		init();
	}

	private String getTempFilePath(String type) {
		String suffix = StringUtils.getFilenameExtension(type);
		String folder = System.getProperty("java.io.tmpdir");
		String tmpFileName = (Math.random() * 10000 + "").replace(".", "");
		return folder + tmpFileName + "." + suffix;
	}
}
